jetcrab\vm\executor\instruction_handlers/
builtin_calls.rs1use crate::runtime::builtins::Builtins;
41use crate::vm::executor::error_handler::ExecutionError;
42use crate::vm::executor::traits::{StackOperations, VariableManager};
43use crate::vm::value::Value;
44
45pub struct BuiltinCallsHandler;
50
51impl BuiltinCallsHandler {
52 pub fn call_builtin<S, V>(
53 stack: &mut S,
54 _variable_manager: &mut V,
55 builtins: &mut Builtins,
56 function_name: String,
57 arg_count: usize,
58 ) -> Result<(), ExecutionError>
59 where
60 S: StackOperations,
61 V: VariableManager,
62 {
63 let mut args = Vec::new();
64 for _ in 0..arg_count {
65 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
66 }
67 args.reverse();
68
69 let result = match builtins.get_function(&function_name) {
70 Some(_) => Value::String(format!("builtin:{}", function_name)),
71 None => Value::Undefined,
72 };
73 stack.push(result);
74 Ok(())
75 }
76
77 pub fn call_console_log<S, V>(
78 stack: &mut S,
79 _variable_manager: &mut V,
80 arg_count: usize,
81 ) -> Result<(), ExecutionError>
82 where
83 S: StackOperations,
84 V: VariableManager,
85 {
86 let mut args = Vec::new();
87 for _ in 0..arg_count {
88 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
89 }
90
91 args.reverse();
92
93 print!("console.log: ");
94 for (i, arg) in args.iter().enumerate() {
95 if i > 0 {
96 print!(" ");
97 }
98 print!("{:?}", arg);
99 }
100 println!();
101
102 stack.push(Value::Undefined);
103 Ok(())
104 }
105
106 pub fn call_console_error<S, V>(
107 stack: &mut S,
108 _variable_manager: &mut V,
109 arg_count: usize,
110 ) -> Result<(), ExecutionError>
111 where
112 S: StackOperations,
113 V: VariableManager,
114 {
115 let mut args = Vec::new();
116 for _ in 0..arg_count {
117 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
118 }
119
120 args.reverse();
121
122 eprint!("console.error: ");
123 for (i, arg) in args.iter().enumerate() {
124 if i > 0 {
125 eprint!(" ");
126 }
127 eprint!("{:?}", arg);
128 }
129 eprintln!();
130
131 stack.push(Value::Undefined);
132 Ok(())
133 }
134
135 pub fn call_parse_int<S, V>(
136 stack: &mut S,
137 _variable_manager: &mut V,
138 arg_count: usize,
139 ) -> Result<(), ExecutionError>
140 where
141 S: StackOperations,
142 V: VariableManager,
143 {
144 let mut args = Vec::new();
145 for _ in 0..arg_count {
146 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
147 }
148 args.reverse();
149
150 let result = if let Some(Value::String(s)) = args.get(0) {
151 let radix = args
152 .get(1)
153 .and_then(|v| {
154 if let Value::Number(n) = v {
155 Some(*n as i32)
156 } else {
157 None
158 }
159 })
160 .unwrap_or(10);
161
162 match i64::from_str_radix(s, radix as u32) {
163 Ok(n) => Value::Number(n as f64),
164 Err(_) => Value::Number(f64::NAN),
165 }
166 } else {
167 Value::Number(f64::NAN)
168 };
169
170 stack.push(result);
171 Ok(())
172 }
173
174 pub fn call_parse_float<S, V>(
175 stack: &mut S,
176 _variable_manager: &mut V,
177 arg_count: usize,
178 ) -> Result<(), ExecutionError>
179 where
180 S: StackOperations,
181 V: VariableManager,
182 {
183 let mut args = Vec::new();
184 for _ in 0..arg_count {
185 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
186 }
187 args.reverse();
188
189 let result = if let Some(Value::String(s)) = args.get(0) {
190 match s.parse::<f64>() {
191 Ok(n) => Value::Number(n),
192 Err(_) => Value::Number(f64::NAN),
193 }
194 } else {
195 Value::Number(f64::NAN)
196 };
197
198 stack.push(result);
199 Ok(())
200 }
201
202 pub fn call_is_nan<S, V>(
203 stack: &mut S,
204 _variable_manager: &mut V,
205 arg_count: usize,
206 ) -> Result<(), ExecutionError>
207 where
208 S: StackOperations,
209 V: VariableManager,
210 {
211 let mut args = Vec::new();
212 for _ in 0..arg_count {
213 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
214 }
215 args.reverse();
216
217 let result = if let Some(Value::Number(n)) = args.get(0) {
218 Value::Boolean(n.is_nan())
219 } else {
220 Value::Boolean(true)
221 };
222
223 stack.push(result);
224 Ok(())
225 }
226
227 pub fn call_is_finite<S, V>(
228 stack: &mut S,
229 _variable_manager: &mut V,
230 arg_count: usize,
231 ) -> Result<(), ExecutionError>
232 where
233 S: StackOperations,
234 V: VariableManager,
235 {
236 let mut args = Vec::new();
237 for _ in 0..arg_count {
238 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
239 }
240 args.reverse();
241
242 let result = if let Some(Value::Number(n)) = args.get(0) {
243 Value::Boolean(n.is_finite())
244 } else {
245 Value::Boolean(false)
246 };
247
248 stack.push(result);
249 Ok(())
250 }
251
252 pub fn call_encode_uri<S, V>(
253 stack: &mut S,
254 _variable_manager: &mut V,
255 arg_count: usize,
256 ) -> Result<(), ExecutionError>
257 where
258 S: StackOperations,
259 V: VariableManager,
260 {
261 let mut args = Vec::new();
262 for _ in 0..arg_count {
263 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
264 }
265 args.reverse();
266
267 let result = if let Some(Value::String(s)) = args.get(0) {
268 let encoded = s
269 .chars()
270 .map(|c| {
271 if c.is_alphanumeric() || "!*'();:@&=+$,/?#[]".contains(c) {
272 c.to_string()
273 } else {
274 format!("%{:02X}", c as u32)
275 }
276 })
277 .collect::<String>();
278 Value::String(encoded)
279 } else {
280 Value::String("".to_string())
281 };
282
283 stack.push(result);
284 Ok(())
285 }
286
287 pub fn call_decode_uri<S, V>(
288 stack: &mut S,
289 _variable_manager: &mut V,
290 arg_count: usize,
291 ) -> Result<(), ExecutionError>
292 where
293 S: StackOperations,
294 V: VariableManager,
295 {
296 let mut args = Vec::new();
297 for _ in 0..arg_count {
298 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
299 }
300 args.reverse();
301
302 let result = if let Some(Value::String(s)) = args.get(0) {
303 let decoded = s
304 .replace("%20", " ")
305 .replace("%2F", "/")
306 .replace("%3F", "?")
307 .replace("%23", "#");
308 Value::String(decoded)
309 } else {
310 Value::String("".to_string())
311 };
312
313 stack.push(result);
314 Ok(())
315 }
316
317 pub fn call_escape<S, V>(
318 stack: &mut S,
319 _variable_manager: &mut V,
320 arg_count: usize,
321 ) -> Result<(), ExecutionError>
322 where
323 S: StackOperations,
324 V: VariableManager,
325 {
326 let mut args = Vec::new();
327 for _ in 0..arg_count {
328 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
329 }
330 args.reverse();
331
332 let result = if let Some(Value::String(s)) = args.get(0) {
333 let escaped = s
334 .chars()
335 .map(|c| match c {
336 'A'..='Z' | 'a'..='z' | '0'..='9' | '@' | '*' | '_' | '+' | '-' | '.' | '/' => {
337 c.to_string()
338 }
339 _ => format!("%{:02X}", c as u32),
340 })
341 .collect::<String>();
342 Value::String(escaped)
343 } else {
344 Value::String("".to_string())
345 };
346
347 stack.push(result);
348 Ok(())
349 }
350
351 pub fn call_unescape<S, V>(
352 stack: &mut S,
353 _variable_manager: &mut V,
354 arg_count: usize,
355 ) -> Result<(), ExecutionError>
356 where
357 S: StackOperations,
358 V: VariableManager,
359 {
360 let mut args = Vec::new();
361 for _ in 0..arg_count {
362 args.push(stack.pop().ok_or(ExecutionError::StackUnderflow)?);
363 }
364 args.reverse();
365
366 let result = if let Some(Value::String(s)) = args.get(0) {
367 let mut unescaped = String::new();
368 let mut chars = s.chars().peekable();
369
370 while let Some(c) = chars.next() {
371 if c == '%' {
372 if let (Some(h1), Some(h2)) = (chars.next(), chars.next()) {
373 if let Ok(byte) = u8::from_str_radix(&format!("{}{}", h1, h2), 16) {
374 unescaped.push(byte as char);
375 continue;
376 }
377 }
378 unescaped.push('%');
379 if let Some(h1) = chars.next() {
380 unescaped.push(h1);
381 }
382 if let Some(h2) = chars.next() {
383 unescaped.push(h2);
384 }
385 } else {
386 unescaped.push(c);
387 }
388 }
389
390 Value::String(unescaped)
391 } else {
392 Value::String("".to_string())
393 };
394
395 stack.push(result);
396 Ok(())
397 }
398}